/**
Cchar: Class holding the character information.
**/
#pragma once

#ifndef _CCHAR_H_
#define _CCHAR_H_



#include "windows.h"
#include "structs.h"

#include "CSemaphore.h"
#include "CStats.h"
#include "CComm.h"
#include "CBaseEntity.h"
#include "CNetwork.h"
#include "CTreasurePool.h"


#define FLAG_GM		0x80
#define FLAG_INVITE 0x00000010
#define FLAG_ANON	0x00000020

DWORD WINAPI CharBattleServ(LPVOID lpParam);
DWORD WINAPI CharItemServ(LPVOID lpParam);

template<class T,class D>class T2List;
class CStringKeyCS;

class CParty;
class CBasicPacket;
class CLinkshell;
class CTradeContainer;
class CItemContainer;
class CItem;
class CWeaponItem;
class CArmorItem;
class CLinkshellItem;
class CNpc;
class CTreasurePool;

struct expChain {

	unsigned short chainNum;
	unsigned int chainStamp;

};

class CChar : public CBaseEntity
{
private: 
	// CChar locks
	CSemaphore* attributeSemaphore;
	CSemaphore* commListSemaphore;
	CSemaphore* recastSpellListSemaphore;
	CSemaphore* recastAbilityListSemaphore;

	//sem_t attributesLockedSemaphore;
	//unsigned int attributeLocker;

	//sem_t commListLockedSemaphore;
	//unsigned int commListLocker;

	//sem_t packetListLockedSemaphore;
	//unsigned int packetListLocker;
public:

	unsigned char m_logoutType; 

	struct connections		clientConn;

	int m_expCurrent;
	unsigned short m_expForNextLevel;

	// Level Cap variable
	unsigned char m_levelCap;

	// struct for holding exp chain info
	struct expChain m_expChain;

	// Level Cap functions
	void setLevelCap(unsigned char levelCap);
	unsigned char getLevelCap();

	// Current Title variable
	unsigned short m_currentTitle;

	unsigned int m_lostExp;
	unsigned short m_hasRaise;
	bool m_hasTractor;

	struct position m_tractorPos;

	// Title functions
	bool hasTitle(unsigned short title);
	void setTitle(unsigned short title);
	unsigned short getCurrentTitle();

	bool inBattle, seeNodes;
	unsigned short onTransport;
	unsigned short boundaryId;
	unsigned short targNode, nodeAction;

	// this is what it reads as, a hack.
	unsigned short m_zoneHack;

	bool loggedIn;
	bool loggedOut;
	bool lsLoginMessageSent;

	bool inEvent;

	// Chardetails
	
	unsigned char firstlogin;

	// only needed at runtime, therefor not in DB.
	unsigned short movCount;

	// Party variables
	unsigned int inParty;
	unsigned int invitePending;
	CParty * m_pParty;

	// Treasure Pool
	CTreasurePool * m_pTreasurePool;

	// last active time
	int aTime;

	// Locks the character during zoning
	unsigned short zoning;
	
	// The last time we recieved information from a client
	unsigned long long lastUpdate;

	// The last time char received mob information
	unsigned long long mobUpdate;

	//This should NOT be unsigned DO NOT CHANGE
	short	pHP,pMP;
	short	pConvHP;
	short	pConvMP;
	short	pHPP;
	short	pMPP;
	short	m_modHPP;
	short	m_modMPP;

	//Target of the used item, usually self
	unsigned int m_itemTarget; 

	struct position m_homePoint;
	struct blowfish enc;

	//Jobs variable
	struct jobs j;
	unsigned long m_subjobUnlocked;

	//Jobs functions
	void unlockSubjobs();
	void unlockJob(unsigned char jobID);

	struct skills s;


	CStats st;
	
	struct keyitems k;

	// Gil
	CItem * gil;
	unsigned long getGil();
	void setGil(unsigned long gil);
	void addGil(unsigned long tmpGil);
	void removeGil(unsigned long tmpGil);
	//gil packet functions
	void sendUpdateGil();

	// Inventory and storages
	CItemContainer * inventory;
	CItemContainer * mogsafe;
	CItemContainer * storage;
	CItemContainer * moglocker;

	// Returns slot where new item is placed
	unsigned char addItem(unsigned short itemID, unsigned char locationID, unsigned long quantity);
	
	CItem * getItem(unsigned char locationID, unsigned char slotID);
	CWeaponItem * getWeaponItem(unsigned char slotID);
	CArmorItem * getArmorItem(unsigned char slotID);
	// Get total quantity of single item in entire inventory or a storage
	unsigned long getItemQuantity(unsigned char locationID, unsigned short itemID);
	void removeItem(unsigned char slotID, unsigned char locationID, unsigned long quantity);
	void removeItemQuantity(unsigned short itemID, unsigned char locationID, unsigned long quantity);
	void moveItem(unsigned char fromLocationID, unsigned char fromSlotID, unsigned char toLocationID, unsigned char toSlotID, unsigned long quantity);
	void useItem(unsigned char slotID);
	void sortInv();

	CLinkshellItem * getLinkshellItem();
	CLinkshell * getLinkshell();
	void setLinkshellSlotID(unsigned char slotID);

	// Load inventory and storages from database at character login
	void loadInvStor();
	// Updates the database - 1 item in an inventory or storage based on slotID
	void updateInvStor(unsigned char locationID, unsigned char slotID);
	// Get size of inventory or a storage
	unsigned char getSizeInvStor(unsigned char locationID);
	// Increase size of inventory or a storage
	void increaseSizeInvStor(unsigned char locationID, unsigned char amount);
	// Move item to inventory or a storage
	unsigned char moveItemToInvStor(CItem * item, unsigned char locationID);
	// Get number of free slots available in inventory or a storage
	unsigned char getFreeSlotCount(unsigned char locationID);
	// Sort inventory or a storage
	void sortInvStor(unsigned char locationID);
	// sends inventory, moghouse and locker size to client.
	void updateInvSize();

	//Returns the characters gender
	unsigned char getGender(void);

	//inventory and storages packet functions
	//Sends item packet for every item in inventory and all storages
	void sendInvStorAll();
	//Sends item packet for 1 item in an inventory or storage
	void sendItemInvStor(unsigned char locationID, unsigned char slotID);
	//Sends update packet for 1 item in an inventory or storage
	void sendUpdateInvStor(unsigned char slotID, unsigned char locationID, unsigned long quantity);
	//Sends "I'm done" packet
	void sendFinishInvStor();

	// Equiping
	unsigned char equip[17];
	void equipItem(unsigned char invSlotID, unsigned char equipSlotID);
	bool equipArmor(unsigned char invSlotID, unsigned char equipSlotID);
	bool equipWeapon(unsigned char invSlotID, unsigned char equipSlotID);
	void unequipItem(unsigned char equipSlotID);

	//Returns the type of weapon
	unsigned char getWeaponType(unsigned char slotID);
	//Returns the base dmg of the current main hand weapon
	unsigned short getWeaponDamage(unsigned char slotID);
	//Get your weapon delay
	unsigned short getDelay(unsigned char slotID);
	//Get character's base attack
	int getBaseAttack();


	// Applies statmods to a char
	void applyStatMod(unsigned char equipSlotID);
	void removeStatMod(unsigned char equipSlotID);

	struct spells sp;

	struct eventQueue eventQ;

	//FAME VARIABLES
	unsigned short fameSan;  // nation 0
	unsigned short fameBas;  // nation 1
	unsigned short fameWin;  // nation 2
	unsigned short fameNorg; // nation 3

	void setFame(unsigned char nation, unsigned short fame);
	unsigned short getFame(unsigned char nation);
	unsigned char getFameLevel(unsigned char nation);

	//Healing variable
	bool m_isHealing;
	long m_healingStartTime;

	//Healing functions
	void isHealing(bool healing);
	bool isHealing();

	//Statuses variable
	unsigned short m_status[32];

	//Statuses functions
	void addStatusIcon(unsigned short statusID);
	void removeStatusIcon(unsigned short statusID);

	//active trade ID
	unsigned int m_tradeID;

	//Trading functions
	unsigned int getTradeID();
	void setTradeID(unsigned int newTradeID);
	bool takeEquipedItem(unsigned char equipSlotID);

	//Packet sending functions for trading
	void sendTradeRequest(unsigned int targId);
	//if both players send accept action, trade complete.
	void sendTradeAction(unsigned long action);
	//add item to trade window
	void sendTradeItem(unsigned short itemID, unsigned long quantity, unsigned char invSlotID, unsigned char tradeSlotID);
	void sendTradeNPC(CTradeContainer * tradeItems);

	//Basic shop variables
	//current shop information.
	unsigned char m_shop[500];
	unsigned char m_shopNation;
	//Stored information from appraisal, for selling.
	unsigned char m_shopInvSlot;
	unsigned long m_shopQuantity;

	//Basic shop functions
	void setShop(unsigned char * shop);
	void buyShop(unsigned char shopSlotID, unsigned long quantity);
	void appraiseShop(unsigned char invSlotID, unsigned short itemID, unsigned long quantity);
	void sellShop();

	void setShopNation(unsigned char nation);
	unsigned char getShopNation();

	//Guild shop functions
	void sendGuildBuy(unsigned short itemID, unsigned char quantity);
	void sendGuildSell(unsigned short itemID, unsigned char slotID, unsigned char quantity);
	void sendGuildBuyMenu();
	void sendGuildSellMenu();

	//Synthing variables
	CTradeContainer * m_synthContainer;
	unsigned long m_synthRecipe;
	unsigned char m_synthResult;

	//Synthing functions
	void setSynth(CTradeContainer * synthContainer);
	CTradeContainer * getSynth();
	void delSynth();

	//Checks if items in container is a recipe
	bool isRecipe(unsigned short crystalItemID);
	//Checks if char has necessary skill to synth recipe
	bool hasSynthSkill();
	//Calculates fail/success/HQ and skill up results
	unsigned char calcSynthResult();
	//Do the results
	void doSynthResult();
	void doSynthSkillUp();
	void doSynthFail();

	//Packet sending fucntions for synthing
	void sendSynth(unsigned short crystalItemID, unsigned char crystalInvSlotID);
	void sendSynthDone();

	//Packet sending function to show NPC text
	void sendNpcText(CBaseEntity * npc, unsigned long messageID);

	//Packet sending function to show special message
	void sendSpecialMessage(unsigned short messageID, unsigned long param1, unsigned long param2, unsigned long param3, unsigned long param4, bool showName);

	//Quest logs variables
	struct questlog {
		bool current[128];
		bool complete[128];
	} m_questLogs[8];

	//Quest logs functions
	void loadQuestMissionLog();
	void setQuestMissionLogStatus(unsigned char logID, unsigned long questMissionID, unsigned char status);
	unsigned char getQuestMissionLogStatus(unsigned char logID, unsigned long questMissionID);

	//Packet sending functions for quest logs
	void sendQuestMissionLog();
	void sendUpdateQuestMissionLog(unsigned char areaID, unsigned char status);

	//Mission log variables
	struct missionlog {
		unsigned long current;
		bool complete[64];
	} m_missionLogs[6];
	struct assaultlog {
		unsigned long current;
		bool complete[128];
	} m_assaultLog;
	struct campaignlog {
		unsigned long current;
		bool complete[512];
	} m_campaignLog;
	struct crystallinelog {
		unsigned long current;
		bool complete[64];
	} m_crystallineLog;
	unsigned long m_copCurrent;
	unsigned long m_acpCurrent;

	//Pet variable
	CNpc * m_pPet;

	//Pet functions
	//Spawn new pet (jugs and summons)
	void spawnPet(unsigned char petID);
	static DWORD WINAPI despawnPet(LPVOID param);

	//Gets the m_pParty Pointer for the party the character belongs to
	CParty * getParty();
	
	//Sets the m_pParty pointer
	void setParty(CParty * party);

	//Returns true if the player is a party member, false if they are not
	bool isPartyMember(CChar * player);

	bool isAllianceMember(CChar * player);

	//Returns the party members in a vector list
	std::vector<CChar*> getPartyMembers();

	//Returns the alliance members in a vector list
	std::vector<CChar*> getAllianceMembers();

	//Returns the party members within a range in a vector list
	std::vector<CChar*> getPartyMembersInRange(position pos,unsigned int range);

	//Returns the party members within the players zone in a vector list
	std::vector<CChar*> getPartyMembersInZone();

	//Returns the alliance members within the players zone in a vector list
	std::vector<CChar*> getAllianceMembersInZone();

	//Returns the party level
	CChar * getHighestLevelCharInParty();

	void distributeExp(int baseExp, CBaseEntity * source);

	// Finds and returns a treasure pool for the character, Will make one if none exist
	CTreasurePool * getTreasurePool();

	// Returns 1 if the treasure pool is not null, returns 0 if it is null
	int hasTreasurePool();

	// Sets the treasure pool
	void setTreasurePool(CTreasurePool * treasurePool);

	// Sends packets to clear the players treasure pool (used on zonein)
	void clearTreasurePool(void);

	//lock operations
	bool tryLockAttributes(void);

	bool lockAttributes(void);
	bool unlockAttributes(void);

	bool lockCommList(void);
	bool unlockCommList(void);

	bool tryLockRecastSpellList(void);
	bool lockRecastSpellList(void);
	bool unlockRecastSpellList(void);

	bool tryLockRecastAbilityList(void);
	bool lockRecastAbilityList(void);
	bool unlockRecastAbilityList(void);


	// list of all commands to be executed for this char
	std::vector<CComm> commList;

	// list of all spells that are cooling down
	std::vector<spellRecast> recastSpellList;

	// list of all spells that are cooling down
	std::vector<abilityRecast> recastAbilityList;

	// list of all Packets to be sent to this char
	T2List<CStringKeyCS, CBasicPacket*>* packetList;
	//std::vector<CBasicPacket> packetList;

	T2List<unsigned int,CBaseEntity*>* hasEnmityList;
	void clearHasEnmityList();

	// list of all npcs/ to be executed for this char
	T2List<int,char>* newSpawnIdList;
	std::vector<int> spawnIDList;

	// std Constructor for CChar
	CChar::CChar();

	// std destructor for CChar
	CChar::~CChar();

	// add char to list
	void CChar::insert(CChar schar);

	// load a char
	bool CChar::loadLook(int charid, bool forLogin);
	int CChar::loadChar(int charid, bool forLogin);

	// creates a new character in the DB
	int CChar::createChar();

	// write char to DB
	void CChar::writeChar();

	void CChar::updateHealth();

	// return a pointer to the char with matching charid or charname 
	static CChar * CChar::getCChar(int charid, char charname[16], int targid);

	// is a char in the specefied zone?
	static bool CChar::isCharInZone(unsigned char zone);

	// confirm players are still connected to the server
	static void CChar::checkChars(void);

	// checks treasure pools for item removal
	static void CChar::checkTreasurePools(void);

	// returns true if the spell currently has cooldown for the char.
	bool CChar::hasSpellCooldown(unsigned int spellID);

	// returns true if the ability currently has cooldown for the char.
	bool CChar::hasAbilityCooldown(unsigned int recastID);

	// add a command to all chars in list with the matching condition
	void CChar::insertComm(int cond, CComm comm, bool hasLock);

	void CChar::insertPacket(int cond, CBasicPacket packet);

	static void CChar::insertPacketGlob(int cond, CBasicPacket packet, CBaseEntity *source);
	// update the chars position and write it to the DB
	void CChar::updatePos(union PacketData pd);

	// send a tell
	int CChar::sendTell(unsigned char * buf, union PacketData pd, unsigned short num);

	// send std chat and intercept commands
	int CChar::sendSay(unsigned char * data, union PacketData pd, unsigned short num);

	// set the chars position
	void CChar::setPosition(float x, float y, float z);

	// que a command for  @command forced zoning
	int CChar::zoneChar(unsigned char to);
	
	// Preforms zoning to specific x,y,z,rotation - no zone lines
	int CChar::zoneChar(unsigned char to,position pos);

	// request to zone
	int CChar::chip(unsigned char *pd, unsigned short num);

	// prepare char for zoning
	int CChar::changeZone(void);

	// get zone for char
	unsigned char CChar::getDisplayZone();

	// actually zone
	void CChar::zoner(void);

	// zoneing using a zoneline
	int CChar::zoneLine(union PacketData pd);

	// process @commands for this char
	int CChar::atCommand(unsigned char * buf, char * data, unsigned short num);

	// logout 
	int CChar::logout(unsigned char * data, unsigned short num, bool removeFromList);

	// allow logout
	int CChar::allowLogout(unsigned char * data, unsigned short num);

	// releases a char from frozen screen
	void CChar::release();

	// custom release for scripters that need it
	void CChar::release(unsigned char releaseType);

	// update the chars health status
	int CChar::health(unsigned char * data, unsigned short num);

	// change the current job and calculate the stats
	void CChar::cmjob(unsigned char job, unsigned char level);

	// change the current subjob
	void CChar::csjob(unsigned char job, unsigned char level);

	// a debugmessage printer... it's buggy btw... heh...
	void CChar::debugMsg(char * buf, ...);

	// stops the "Downloading Data..." msg
	int CChar::stopDld(unsigned char * data, unsigned short num);;

	// change flags (/inv /anon and the like) still buggy.
	void CChar::updateChar();

	// Spawn other players
	//int CChar::spawnPCs(unsigned char * data, unsigned short num);
	void CChar::spawnPCs(void);

	// recieve chat
	int CChar::recvChat(unsigned char * data, unsigned short num, CComm * comm);

	// send an error msg to the char
	int CChar::sendErr(unsigned char * data, unsigned short num, unsigned short n);

	// checking of players and monsters. monsters still missing.
	void CChar::check(int charid);

	// recieving of standart FFXI messages - DEPRECATED
	//int CChar::stdmRecv(unsigned char * data, CComm * comm, unsigned short num);

	// sending of an emote action
	int CChar::emote(unsigned char * data, char * in, unsigned short num);

	// recieving of an emote action
	int CChar::emoteRecv(unsigned char * data, CComm * comm, unsigned short num);

	// response the the server message request
	void CChar::sendServerMessage();

	// NOT USED ATM
	int CChar::updatePCs(unsigned char * data, CComm * comm, unsigned short num);

	// /random action
	int CChar::diceroll(unsigned char * data, unsigned short num);

	// animation change to sit.
	void CChar::tsit(unsigned char * data, char * in, unsigned short num);

	// invite, anon flag switch. still buggy.
	int CChar::seekAnon(unsigned char * data, char * in, unsigned short num);

	// changes job while in moghouse.  DEPRECATED
	//int CChar::cmJobMog(unsigned char * data,  char * in, unsigned short num);

	// response to the 16c (character request packet)
	int CChar::reqChar(unsigned char * data,  char * in, unsigned short num);
	
	void CChar::updateKeyItems();

	// Send Spell Packet to char
	void CChar::updateSpells();

	// Send Abilities Packet to char
	void CChar::updateAbilities();

	// Sends the mog menu to char
	void CChar::sendMogMenu();

	// A Player level packet?
	void CChar::sendLevel();

	// Add items to commList
	int CChar::addCommList(CComm comm);

	// puts a packet into the send queue
	int CChar::quePacket(CBasicPacket pack);

	// Returns the maximum HP or MP with stat modifications
	int CChar::getMaxHp();
	int CChar::getMaxMp();

	bool CChar::hasKeyItem(int keyItemId);
	bool CChar::seenKeyItem(int keyItemId);

	//Test if character has the spell
	bool CChar::hasSpell(int spellId);  

	//Returns the exp needed for the next level
	unsigned short CChar::getExpForNextLevel();

	//adds exp to the char
	void CChar::gainExp(int baseExp);

	//Level-up
	void CChar::gainLevel();

	//Get skill value by skill id
	unsigned short CChar::getSkill(unsigned short id);

	//Set skill value by skill id
	void CChar::setSkill(unsigned short id, unsigned short value);

	//Increment skill id by value
	void CChar::incSkill(unsigned short id, unsigned short value);
	
	//Get skill rank by skill id
	unsigned char CChar::getSkillRank(unsigned short id);

	//Get max skill of any skill id
	unsigned short CChar::getMaxSkill(unsigned short id);
	
	//Do skillup for skill id
	void CChar::doSkillUp(unsigned char skillID, unsigned short checkSkill);

	//Teaches weaponskill id
	void CChar::learnWeaponSkill(unsigned short id);

	//Attack for damage
	void CChar::attackAction(CBaseEntity* target);
	
	void CChar::sendCharUpdate();

	void CChar::lockOn(CBaseEntity * target);

	void CChar::disengage();

	void CChar::engage(CBaseEntity * target);

	void CChar::takePhysicalDamage(int damage, CBaseEntity * pDamageDealer);

	void CChar::die();

	void CChar::loseExp(int lostExp) ;

	//Level Down :/
	void CChar::loseLevel();

	int	CChar::setCharVar(const char * variable, int value);

	int	CChar::getCharVar(const char * variable);

	int CChar::getFStr(CBaseEntity * target);
	int CChar::getFStrTwo(CBaseEntity * target);

	int getBaseAccuracy(CBaseEntity * target, unsigned int weaponslot = SLOT_MAIN);

	unsigned int getBaseEva();

	int getBaseDef();

	unsigned short CChar::getHitRate(CBaseEntity * target, unsigned int weaponslot);

	// Set character boundary ID to result from 0xF2 client packet
	void CChar::setBoundary(unsigned short boundaryNum);

	// Invites another player to a party
	int CChar::sendPartyInvite(CChar * invitee);

	// Handles a party accept or decline
	int CChar::partyInviteHandler(unsigned int result);

	// Sends the players stats to everyone in the party
	int CChar::updatePartyStats(void);

	//Forces the player to leave a party (used if a player disconnects)
	int CChar::forcePartyLeave(void);

	//Updates the party members locations on your map
	int CChar::sendPartyMembersMap();

	// Delete a character from the db
	static void CChar::deleteChar(unsigned int charId);

	// Set character's UDP socket
	void CChar::setUdpPort(u_short socket);

	// remove char from charlist
	void removeFromAllLists(); 

	//functions overloaded from CBaseEntity
	void setTargId(unsigned int targid);

	// return the amount of EXP after applied caps
	int getCappedExp(int baseExp);

	// returns the time to kill a mob to keep the chain
	int getExpChainTimer();

	bool isExpChain();

	float getExpChainMod();

	void sendRaiseMenu();

	void sendTractorMenu();

	void gainTPFrom(int weaponslot, CBaseEntity * target);
	unsigned int getNumAttacksFrom(int weaponslot);
	
	unsigned int getCritHitRateOn(CBaseEntity * pTarget);

	unsigned short m_costume;
};


#endif
